; > Kbd

; Source for A4000 8051-based keytronic keyboard
;
; Author:       Tim Dobson, modified for keytronic hardware by Alex Bienek
; Version:      1.00
; Status:       Release
; Started:      08-Dec-88
; Last updated: 15-Aug-92
; 

        GBLS    Title
        GBLS    Version
        GBLS    NewLine

NewLine SETS    :CHR:10 :CC: :CHR:13
Title   SETS    "8051 keytronic controller" :CC: NewLine
Title   SETS    Title :CC: "(C) Acorn Computers Ltd, 1992" :CC: NewLine
Version SETS    "Version 1.00 (15-Aug-92)"

        GET     Hdr.Macros8051
        GET     Hdr.SFRs
        GET     Hdr.Hardware
        GET     Hdr.Def

        GBLL    Debug_On
Debug_On SETL   {FALSE}

        GBLL    Debug_ResetState
Debug_ResetState SETL   {FALSE}


OV_bit  Bit     PSW, 2
MI_bit  Bit     ACC, 7
ACC_7   Bit     ACC, 7
ACC_6   Bit     ACC, 6
ACC_5   Bit     ACC, 5
ACC_4   Bit     ACC, 4
ACC_3   Bit     ACC, 3
ACC_2   Bit     ACC, 2
ACC_1   Bit     ACC, 1
ACC_0   Bit     ACC, 0

B_0     Bit     B, 0

        ^       &00             ; register bank 0
KBDBank #       0
MouseBank #     0

; The next two MUST be R0 and R1 in some order (used as ptrs)

StablePtr #     1               ; points to stable state for current row
XORPtr    #     1               ; points to last XOR for current row

KBDRow    #     1               ; current row number (0*8..14*8)
                                ; (bottom 3 bits hold column while outputting
                                ; key transitions)

OldData   #     1               ; old mouse quadrature data
XDir      #     1               ; mouse X velocity (used for hysteresis)
YDir      #     1               ; mouse Y velocity (used for hysteresis)
MouseX    #     1               ; mouse X position (since last sent)
MouseY    #     1               ; mouse Y position (since last sent)

        ASSERT  @ <= &08

        ^       &08             ; register bank 1
IrqBank    #    0

; The next two MUST be R0 and R1 in some order (used as ptrs)

HeadPtr    #    1               ; where key transitions get inserted
TailPtr    #    1               ; where key transitions get removed from

ResetState #    1               ; value to send or receive
Byte2      #    1               ; 2nd byte of 2 byte protocol
KBID       #    1               ; keyboard ID
SPDData    #    1               ; SPD conversion data

        ASSERT  @ <= &10

; Bit data

        ^       0               ; bit address

MouseMoved      #       1       ; set when mouse moved or RQMP received
                                ; cleared when mouse data transmitted

MouseOverflow   #       1       ; set when counter(s) have overflowed
                                ; cleared when mouse data transmitted

MouseEnabled    #       1       ; set when RQMP or MACK or SMAK received
                                ; cleared when mouse data transmitted

KeysEnabled     #       1       ; set when SACK or SMAK received
                                ; cleared when key info sent

InError         #       1       ; set when we are about to transmit the 1st FF

Resetting       #       1       ; when set, we are in reset protocol

ResetTXNotRX    #       1       ; set when TX OK during reset protocol
                                ; clear when RX OK during reset protocol

TXIdle          #       1       ; set when TI happens and there is nothing to
                                ; transmit; cleared (and TI set) when there is
                                ; something to transmit

InProtocol      #       1       ; set when in a 1-byte or 2-byte protocol

ExpectBACK      #       1       ; set after transmitting 1st of 2 byte packet
                                ; cleared after receiving BACK

SendByte2       #       1       ; set to indicate that Byte2 should be sent
                                ; cleared when byte 2 is sent

ExpectACK       #       1       ; set after last byte of protocol has been sent
                                ; also set when expect ACK after reset protocol
                                ; cleared after an ACK has been received

SendKBID        #       1       ; set to indicate that KBID should be sent

SendPDAT        #       1       ; set to indicate that PDAT should be sent

CapsLockStatus  #       1       ; status of CAPS lock (for saving over reset)
ScrollLockStatus #      1       ; status of SCROLL lock (--------""---------)
NumLockStatus   #       1       ; status of NUM lock  (----------""---------)

MatrixPort      #       1       ; 0 means P1, 1 means P2

        ASSERT  @ <= &40

; Indirectly accessed data

        ^       &28
StableStates    #       29      ; stable states of keys (0=down, 1=up)
                                ; indexed by row number
                                ; (0..15 from P1, 16..27 from P2, 28 mouse buttons)
                                ; (8 columns,     8 columns,      top 3 bits)

LastTimeXOR     #       29      ; indicates which keys changed last scan
                                ; (0=no change, 1=changed)

KeyTranBuffer   #       9       ; buffer for key transitions (8+1 unused slot)
KeyTranBufEnd   #       0

ResetID         #       3       ; 3-byte ID used to identify power-on resets

StackBase       #       0       ; use from here upwards for the stack

ResetID0 * &54                  ; 3-byte 'random' pattern stored in memory -
ResetID1 * &69                  ; if pattern not there after reset, then must
ResetID2 * &6D                  ; be power-on reset

ID       * &81                  ;returned ID
                
NumMask  * &10
CapMask  * &20
ScrollMask * &40

TMODValue * TMOD_T1_NoGate :OR: TMOD_T1_Timer :OR: TMOD_T1_8BitReload :OR: TMOD_T0_NoGate :OR: TMOD_T0_Timer :OR: TMOD_T0_16Bit

SCONValue * SCON_9BitVariable :OR: SCON_Check9thBit :OR: SCON_TB8 :OR: SCON_REN

; Timer 0 is used to create a delay of 600s between each row scan.
; This makes a complete scan take 28 rows * 600s = 17ms + time for polling
; mouse and checking result of kbd scan, making it about 18ms ie reasonable
; debounce period. Also allows plenty of time for keyboard capacitance to
; die away.

Timer0Value *   &10000-600

        ORG     0

; Reset

        NoRP
        org     &00
ResetV
        ajmp    Reset

; External interrupt 0

        NoRP
        org     &03
        ajmp    BadReset

; Timer 0 interrupt

        NoRP
        org     &0B
        ajmp    BadReset

; External interrupt 1

        NoRP
        org     &13
        ajmp    BadReset

; Timer 1 interrupt

        NoRP
        org     &1B
        ajmp    BadReset

; Serial interrupt

        NoRP
        org     &23
        ajmp    SerialIRQ

; Timer 2 or External interrupt 2

        NoRP
        org     &2B
        ajmp    BadReset

        =       Title
        =       Version, 0

; *****************************************************************************

        RPIs    IrqBank
RXReset
        jb      ResetTXNotRX, GoRXExit
        jb      ExpectACK, GoResetACK
        cjne    A, ResetState, TryHRST  ; if not correct char, check for HRST
        setb    ResetTXNotRX
RXExitWakeUpTX
        acall   WakeUpTX                ; restart transmission if necessary
GoRXExit
        ajmp    RXExit                  ; and exit

GoResetACK
        ajmp    ResetACK

TryHRST
        cjne    A, #K1hrst, BombOutToError
        sjmp    BombOutToRestart

TryRQPD
        jb      ACC_5, BombOutToError
        jb      ACC_4, BombOutToError
        xrl     A, #(K1pdat :EOR: K1rqpd)
        mov     SPDData, A
        setb    SendPDAT
        sjmp    RXExitWakeUpTX

RXReqOrACK
        jb      ACC_4, RXACK

; It's a request

        cjne    A, #K1rqid, NotRQID
        setb    SendKBID
        sjmp    RXExitWakeUpTX

NotRQID
        cjne    A, #K1prst, NotPRST
        sjmp    RXExit

NotPRST
        cjne    A, #K1rqmp, BombOutToError
        setb    MouseEnabled
        setb    MouseMoved
        sjmp    RXExitWakeUpTX

RXACK
        cjne    A, #K1back, RXNormalACK
        jnb     ExpectBACK, BombOutToError
        clrb    ExpectBACK
        setb    SendByte2
        sjmp    RXExitWakeUpTX

RXNormalACK
        jb      ACC_3, BombOutToError
        jb      ACC_2, BombOutToError
        jnb     ExpectACK, BombOutToError
        clrb    ExpectACK
        clrb    InProtocol
        rrc     A
        mov     KeysEnabled, C
        rrc     A
        mov     MouseEnabled, C
        sjmp    RXExitWakeUpTX

RXIRQ
        mov     A, SBUF                 ; read character
        [ Debug_On
        lcall   DebugRX
        ]
        jb      Resetting, RXReset
        jb      ACC_7, TryHRST          ; if top bit set then must be reset
        jb      ACC_6, TryRQPD
        jb      ACC_5, RXReqOrACK

        jb      ACC_4, BombOutToError
        jb      ACC_3, BombOutToError

; Now set LED states

        mov     C, ACC_0
        mov     CapsLockStatus, C
        mov     CapsLockLED, C
        mov     C, ACC_1
        mov     NumLockStatus, C
        mov     NumLockLED, C
        mov     C, ACC_2
        mov     ScrollLockStatus, C
        mov     ScrollLockLED, C
        sjmp    RXExit

; *****************************************************************************

BombOutToError
        setb    InError
BombOutToRestart
        clrb    EA                      ; disable IRQs for after the reti
        mov     StackBase+0, #(Restart :AND: &FF)
        mov     StackBase+1, #(Restart / &100)
        mov     SPTR, #StackBase+1      ; point stack at fake return address
        reti

SerialIRQ
        push    PSW
        push    ACC
        SetRP   IrqBank
        jbc     RI, RXIRQ
RXExit
        [ Debug_On :LAND: Debug_ResetState
        mov     A, #""I""               ; DEBUGGING
        lcall   BufferByte              ; DEBUGGING
        lcall   DebugResetState         ; DEBUGGING
        ]
        jbc     TI, TXIRQ
TXExit
        pull    ACC
        pull    PSW
AReti
        reti

; *****************************************************************************

        RPIs    IrqBank
TXIRQ
        jbc     InError, TXInError
        jb      Resetting, TXReset
        jb      InProtocol, TXInProtocol
        jbc     SendKBID, TXSendKBID
        jbc     SendPDAT, TXSendPDAT
        jnb     KeysEnabled, DontSendKeys

; Now check if any key transitions in buffer

        mov     A, TailPtr              ; if pointers different then
        cjne    A, HeadPtr, TXKeyTrans  ; there are transitions to transmit

DontSendKeys
        jnb     MouseEnabled, TXGoIdle
        jnb     MouseMoved, TXGoIdle

; Send mouse data

        mov     A, MouseY               ; shift zero into top bit of Y coord
        clrb    C
        rrc     A
        mov     Byte2, A                ; and send that after this

        clr     A
        mov     MouseY, A               ; zero MouseY
        xch     A, MouseX               ; read MouseX and zero it
        clrb    C                       ; shift zero into top bit of X coord
        rrc     A

        clrb    MouseMoved
        clrb    MouseEnabled
        clrb    MouseOverflow
TX2Byte
        setb    InProtocol
        setb    ExpectBACK
        sjmp    TXSendAcc

TXInError
        mov     A, #K1hrst
TXSendAccWaitForRX
        clrb    ResetTXNotRX
TXSendAcc
        mov     SBUF, A
        [ Debug_On
        lcall   DebugTX
        ]
        ajmp    TXExit

TXReset
        jnb     ResetTXNotRX, TXGoIdle
        mov     A, ResetState
        dec     ResetState
        cjne    ResetState, #K1rak2-1, TXSendAccWaitForRX
        setb    ExpectACK
        sjmp    TXSendAccWaitForRX

TXInProtocol
        jbc     SendByte2, TXSendByte2
TXGoIdle
        setb    TXIdle
        ajmp    TXExit

TXSendByte2
        mov     A, Byte2
        setb    ExpectACK
        sjmp    TXSendAcc

TXSendKBID
        mov     A, KBID
        setb    ExpectACK
        setb    InProtocol
        sjmp    TXSendAcc

TXSendPDAT
        mov     A, SPDData
        setb    ExpectACK
        setb    InProtocol
        sjmp    TXSendAcc

; transmit a key transition

TXKeyTrans
        mov     A, @TailPtr
        inc     TailPtr
        cjne    TailPtr, #KeyTranBufEnd, NoRemoveWrap
        mov     TailPtr, #KeyTranBuffer
NoRemoveWrap
        mov     C, ACC_7                ; 0 => down, 1 => up
        push    ACC
        anl     A, #&0F                 ; get lo-nibble (to be send 2nd)
        orl     A, #K1kdda              ; merge with protocol bits
        mov     ACC_4, C                ; specify up or down
        mov     Byte2, A

        pull    ACC
        swap    A                       ; send hi-nibble first
        anl     A, #&07                 ; hi nibble is only 3 bits
        orl     A, #K1kdda              ; merge with protocol bits
        mov     ACC_4, C
        sjmp    TX2Byte

; *****************************************************************************

        RPIs    IrqBank

GoTryHRST
        ajmp    TryHRST

ResetACK
        jb      ACC_7, GoTryHRST
        jb      ACC_6, GoBombOutToError
        jnb     ACC_5, GoBombOutToError
        jnb     ACC_4, GoBombOutToError
        jb      ACC_3, GoBombOutToError
        jb      ACC_2, GoBombOutToError

        push    ACC

        SetRP   MouseBank
        mov     A, MouseInput
        orl     A, #(&FF :EOR: MouseMask) ; just get mouse data
        mov     OldData, A
        clr     A
        mov     XDir, A
        mov     YDir, A
        mov     MouseX, A
        mov     MouseY, A
        clrb    MouseMoved
        clrb    MouseOverflow
        clrb    Resetting

        SetRP   IrqBank
        mov     HeadPtr, #KeyTranBuffer ; initialise buffer pointers
        mov     TailPtr, #KeyTranBuffer
        pull    ACC
        ajmp    RXNormalACK

GoBombOutToError
        ljmp    BombOutToError

; *****************************************************************************

        NoRP
WakeUpTX
        jbc     TXIdle, TXasleep
        ret
TXasleep
        setb    TI
        ret

; *****************************************************************************

; Come here if we get an unexpected IRQ (shouldn't happen)

BadReset
        mov     IE, #0                  ; disable all IRQs
        mov     SPTR, #StackBase-1      ; set up stack pointer
        lcall   AReti                   ; make sure the processor doesn't think
                                        ; we're in an IRQ routine ?

; Come here on a reset

Reset
        mov     IE, #IE_ES              ; enable serial IRQ (but all IRQs off)
        mov     SPTR, #StackBase-1
        mov     IP, #0                  ; all interrupts low priority
        mov     PCON, #PCON_BaudNormal
        mov     TCON, #TCON_TR0 :OR: TCON_TR1 ; start timers
        mov     TMOD, #TMODValue
        mov     SCON, #SCONValue
        mov     Timer1Latch, #&FF       ; baud rate = 12E6/(384*(256-latch))
                                        ; = 31250
        mov     MainInput1, #&FF        ; all inputs (P1)
        mov     MainInput2, #&7F        ; all inputs (P2)
        mov     P0, #&00                ; all outputs(P0 row enc. & leds)
        mov     P3, #&FF                ; set mouse buttons and serial in to
                                        ; inputs

; Now check 3-byte ID - if intact, then it's a soft reset, else it's a power-on

        SetRP   0
        mov     R0, #ResetID
        cjne    @R0, #ResetID0, PowerOnReset
        inc     R0
        cjne    @R0, #ResetID1, PowerOnReset
        inc     R0
        cjne    @R0, #ResetID2, PowerOnReset
        sjmp    SoftReset

; It's power-on, so clear out RAM (including stack!)

PowerOnReset
        mov     R0, #&7F
        clr     A
ZeroRAMLoop
        mov     @R0, A
        djnz    R0, ZeroRAMLoop

; Initialise 3-byte ID

        mov     ResetID+0, #ResetID0
        mov     ResetID+1, #ResetID1
        mov     ResetID+2, #ResetID2
SoftReset

; now put back old LED status

        mov     C, CapsLockStatus
        mov     CapsLockLED, C
        mov     C, ScrollLockStatus
        mov     ScrollLockLED, C
        mov     C, NumLockStatus
        mov     NumLockLED, C

        [ Debug_On
        lcall   DebugReset
        ]
        lcall   ReadKBID                ; corrupts register bank
        NoRP

        setb    TXIdle
        setb    InError                 ; indicate sending 1st &FF
Restart
        mov     SPTR, #StackBase-1
        mov     ResetState, #K1hrst
        setb    Resetting
        setb    ResetTXNotRX
        clrb    ExpectACK
        clrb    ExpectBACK
        clrb    SendByte2
        clrb    InProtocol
        clrb    SendKBID
        clrb    SendPDAT
        setb    MatrixPort
        acall   WakeUpTX
        setb    EA                      ; enable IRQs

WaitForResetToFinish
        jb      Resetting, WaitForResetToFinish

        lcall   InitKeys

        SetRP   MouseBank
MainLoop
        acall   PollMouse
        jnb     KeysEnabled, MainLoop   ; if keys not wanted, just poll mouse
        jnb     TF0, MainLoop           ; timer not exhausted, carry on polling

; It's time to scan the next row of the keyboard

        ASSERT  KBDBank=MouseBank

        cjne    KBDRow, #28*8, NotMouseButtons

;ItsMouseButtons
        mov     A, MouseButtonInput2            ;this gives us switch 3 in bit 6
        rlc     A                               ;get switch state into carry
        rlc     A
        mov     A, MouseButtonInput1            ;then read sw 2 & 1 into bits 7 and 6
        rrc     A                               ;and retrieve switch 3
        orl     A, #&FF :EOR: MouseButtonMask   ; set other bits to 1
        sjmp    DoScan

NotMouseButtons
        cjne    KBDRow, #15*8, CheckPortFlag
        clrb    MatrixPort

CheckPortFlag
        jnb     MatrixPort, UsePort1

;UsePort2
        mov     A, MainInput2
        sjmp    DoScan

UsePort1
        mov     A, MainInput1

DoScan
        xrl     A, @StablePtr           ; new difference from stable state
        xch     A, @XORPtr              ; swap new and old differences
        anl     A, @XORPtr              ; get stable differences
        jz      KeyNoChange             ; none, so we've done this row

        mov     DPTR, #KBDTran

; now XOR both stable state and last XOR with stable difference, preserving A

        xch     A, @XORPtr
        xrl     A, @XORPtr
        xch     A, @XORPtr

        xch     A, @StablePtr
        xrl     A, @StablePtr           ; A now holds new stable value
        mov     B, A                    ; save it away so we know up or down
        xch     A, @StablePtr

        dec     KBDRow                  ; we don't want first increment
        clrb    C                       ; to fill top bits with zero
IncLoop
        inc     KBDRow                  ; increment offset into table
        rrc     A                       ; shift next bit into carry
        jc      FoundBit                ; if set, it's a key transition
NextBit
        xch     A, B                    ; shift stable state byte
        rr      A                       ; preserves carry (should be clear)
        xch     A, B
        jnz     IncLoop                 ; if A still has bits in it then loop

KeyNoChange
        mov     A, KBDRow
        anl     A, #&F8                 ; knock out the column bits
        dec     StablePtr
        dec     XORPtr
        clrb    C
        subb    A, #&08                 ; go to previous row
        acall   SetRow
        sjmp    MainLoop

FoundBit
        push    ACC
        mov     A, KBDRow
        movc    A, @A+DPTR
        jb      ACC_7, InvalidKey
        acall   OutputKeyTransition
InvalidKey
        pull    ACC
        clrb    C
        sjmp    NextBit

OutputKeyTransition
        mov     C, B_0
        mov     ACC_7, C                ; bit 7 set => key up not down
        SetRP   IrqBank
        mov     @HeadPtr, A
        mov     A, HeadPtr
        inc     A
        cjne    A, #KeyTranBufEnd, NoInsertWrap
        mov     A, #KeyTranBuffer
NoInsertWrap
        cjne    A, TailPtr, BufferNotFull

; buffer is full so poll mouse while we're waiting

        push    DPH
        push    DPL
        push    ACC
        push    PSW
        SetRP   MouseBank
        acall   PollMouse
        pull    PSW
        pull    ACC
        pull    DPL
        pull    DPH
        sjmp    NoInsertWrap

BufferNotFull
        mov     HeadPtr, A
        acall   WakeUpTX
        SetRP   KBDBank
        ret

; *****************************************************************************
;
;       InitKeys - Initialise StableStates to 1 and LastTimeXOR to 0,
;       set KBDRow to 14*8, StablePtr to StableStates+14,
;       XORPtr to LastTimeXOR+14, set hardware row select to 14,
;       then initialise timer 0
;

InitKeys
        SetRP   KBDBank
        mov     KBDRow, #29             ; temporary counter
        mov     StablePtr, #StableStates+28
        mov     XORPtr, #LastTimeXOR+28
        clr     A
InitKeyLoop
        mov     @XORPtr, A
        mov     @StablePtr, #&FF
        dec     XORPtr
        dec     StablePtr
        djnz    KBDRow, InitKeyLoop

        setb    C
SetRow
        jnc     SetRowAcc
        setb    MatrixPort
        mov     A, #28*8
        mov     StablePtr, #StableStates+28
        mov     XORPtr, #LastTimeXOR+28
SetRowAcc
        mov     KBDRow, A
        swap    A
        rl      A                       ; move row to bits 0..3
        anl     A, #&0F
; Now we must set up the LEDs
        jnb     NumLockStatus, TestCapsLock
        orl     A, #NumMask
TestCapsLock
        jnb     CapsLockStatus, TestScrollLock
        orl     A, #CapMask
TestScrollLock
        jnb     ScrollLockStatus, SetRowLeds
        orl     A, #ScrollMask
SetRowLeds
        mov     MatrixOutput, A

; Now start timer again

        clrb    TR0
        mov     TL0, #(Timer0Value :AND: 255)
        mov     TH0, #(Timer0Value/256)
        clrb    TF0
        setb    TR0
        ret

; *****************************************************************************
;
;       ReadKBID - Read keyboard ID and store in KBID variable
;

ReadKBID
        SetRP   KBDBank
        mov     KBID, #ID
        ret

; *****************************************************************************
;
;       PollMouse - Routine to check mouse quadrature signals and
;       update mouse coordinates
;
; in:   RP = MouseBank
;

        RPIs    MouseBank
PollMouse
        mov     A, MouseInput           ; load mouse data
        rl      A                       ; and get into top 4 bits
        rl      A
        orl     A, #(&FF :EOR: MouseMask) ; ignore other bits
        cjne    A, OldData, Changed     ; if same
        ret                             ; then exit

Changed
        xch     A, OldData              ; store back new data and get old
        swap    A                       ; move old data to other nibble
        anl     A, OldData              ; get old and new data in 2 nibbles
        mov     DPL, A

        mov     DPH, #XTablesBase/256  ; point to 1st X table (zero)
        mov     A, XDir
        jz      ZeroXDir                ; if XDir=0 then that's it
        inc     DPH                     ; else add 1
        jb      MI_bit, NegXDir         ; and if XDir>0
        inc     DPH                     ; then add another one
NegXDir
        clr     A
ZeroXDir
        movc    A, @A+DPTR              ; load value 
        mov     XDir, A

        mov     DPH, #YTablesBase/256   ; point to 1st Y table (zero)
        mov     A, YDir
        jz      ZeroYDir                ; if YDir=0 then that's it
        inc     DPH                     ; else add 1
        jb      MI_bit, NegYDir         ; and if YDir>0
        inc     DPH                     ; then add another one
NegYDir
        clr     A
ZeroYDir
        movc    A, @A+DPTR              ; load value 
        mov     YDir, A

        jb      MouseOverflow, NoAdd
        push    IE                      ; save interrupt state
        clrb    EA                      ; disable IRQs while we modify
                                        ; mouse coordinates
        mov     A, MouseX
        add     A, XDir
        jb      OV_bit, XOverflow
XOverflowReturn
        mov     MouseX, A
        mov     A, MouseY
        add     A, YDir
        jb      OV_bit, YOverflow
YOverflowReturn
        mov     MouseY, A
        setb    MouseMoved              ; only set this after coords updated
        jnb     MouseEnabled, DontWakeTX
        acall   WakeUpTX
DontWakeTX
        pull    ACC                     ; pull IRQ status into accumulator
        jnb     ACC_7, NoAdd            ; if IRQs disabled before, do nowt
        setb    EA
NoAdd
        ret

XOverflow
        setb    MouseOverflow
        jb      MI_bit, XMaxPos ; if -ve now then should be max +ve
        mov     A, #&80         ; else +ve now so should be max -ve
        sjmp    XOverflowReturn
XMaxPos
        mov     A, #&7E
        sjmp    XOverflowReturn
        
YOverflow
        setb    MouseOverflow
        jb      MI_bit, YMaxPos ; if -ve now then should be max +ve
        mov     A, #&80         ; else +ve now so should be max -ve
        sjmp    YOverflowReturn
YMaxPos
        mov     A, #&7E
        sjmp    YOverflowReturn
        
; Now the keyboard translation table

        GET     KbdTran

; Now the mouse tables

        ALIGN   256
        GET     Obj.MouseTable

; *****************************************************************************

        [ Debug_On

; Debug routines

        NoRP

DebugReset
        push    ACC
        mov     A, #""X""
        sjmp    DebugChar

        [ Debug_ResetState
DebugResetState
        push    ACC
        mov     A, #""S""
        acall   BufferByte
        mov     A, ResetState
        acall   BufferByte
        pull    ACC
        ret
        ]

DebugTX
        [ Debug_ResetState
        acall   DebugResetState
        ]
        push    ACC
        mov     A, #""T""
        sjmp    DebugChar

DebugRX
        [ Debug_ResetState
        acall   DebugResetState
        ]
        push    ACC
        mov     A, #""R""
DebugChar
        acall   BufferByte
        pull    ACC
        push    ACC
        acall   BufferByte
        pull    ACC
        ret

BufferByte
        push    DPH
        push    DPL
        push    ACC
        mov     DPTR, #&1000
        movx    A, @DPTR        ; get high byte of pointer
        push    ACC
        inc     DPTR            ; move DPTR on to &1001
        movx    A, @DPTR        ; get lo byte of pointer
        mov     DPL, A
        pull    DPH             ; DPTR now points to insertion point
        pull    ACC
        movx    @DPTR, A        ; store byte
        inc     DPTR
        mov     A, DPH
        jb      ACC_7, BufferFull
        push    DPL             ; save lo-byte of new pointer
        mov     DPTR, #&1000
        movx    @DPTR, A        ; store hi-byte back
        pull    ACC
        inc     DPTR
        movx    @DPTR, A        ; store lo-byte back
BufferFull
        pull    DPL
        pull    DPH
        ret

        ]

        WHILE   . < &1000
        =       &FF
        WEND

        END

